﻿using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Collections.Generic;

namespace Engine2D
{
    public class SceneObject
    {
        private Scene mScene;
        private VertexBuffer mVertexBuffer;
        private IndexBuffer mIndexBuffer;
        private IList<Triangle> mTriangles;

        public float Width { get { return 1.0f; } }
        public float Height { get { return 1.0f; } }

        public Scene Scene
        {
            get { return mScene; }
            set
            {
                if (mScene != null)
                    DisposeBuffers();
                mScene = value;
                if (mScene != null)
                    InitBuffers();
            }
        }

        public Texture2D Texture { get; set; }
        public Vector3 Position { get; set; }
        public Matrix Rotation { get; set; }
        public Matrix Scale { get; set; }

        public SceneObject()
        {
            Position = new Vector3(0, 0, 0);
            Rotation = Matrix.Identity;
            Scale = Matrix.Identity;
            mTriangles = new List<Triangle>();
        }

        private void InitBuffers()
        {
            mVertexBuffer = new VertexBuffer(mScene.GraphicsDevice, typeof(SceneVertex), 4, BufferUsage.WriteOnly);
            mIndexBuffer = new IndexBuffer(mScene.GraphicsDevice, typeof(short), 6, BufferUsage.WriteOnly);

            SceneVertex[] verts = new SceneVertex[4];
            verts[0] = new SceneVertex(new Vector3(-0.5f, 0.5f, 0), new Vector3(0, 0, 1), Color.White.ToVector3(), new Vector2(0, 0));
            verts[1] = new SceneVertex(new Vector3(-0.5f, -0.5f, 0), new Vector3(0, 0, 1), Color.White.ToVector3(), new Vector2(0, 1));
            verts[2] = new SceneVertex(new Vector3(0.5f, -0.5f, 0), new Vector3(0, 0, 1), Color.White.ToVector3(), new Vector2(1, 1));
            verts[3] = new SceneVertex(new Vector3(0.5f, 0.5f, 0), new Vector3(0, 0, 1), Color.White.ToVector3(), new Vector2(1, 0));

            short[] indices = new short[]
            {
                0, 1, 2,
                2, 3, 0
            };

            mVertexBuffer.SetData<SceneVertex>(verts);
            mIndexBuffer.SetData<short>(indices);

            mTriangles.Clear();
            for (int i = 0; i < indices.Length; i += 3)
            {
                int idxA = indices[i];
                int idxB = indices[i+1];
                int idxC = indices[i+2];

                Vector3 a = verts[idxA].Position;
                Vector3 b = verts[idxB].Position;
                Vector3 c = verts[idxC].Position;

                Triangle tri = new Triangle(a, b, c);
                mTriangles.Add(tri);
            }
        }

        private void DisposeBuffers()
        {
            mVertexBuffer.Dispose();
            mIndexBuffer.Dispose();
        }

        public void Draw(GameTime gameTime)
        {
            mScene.GraphicsDevice.SetVertexBuffer(mVertexBuffer);
            mScene.GraphicsDevice.Indices = mIndexBuffer;
            mScene.GraphicsDevice.Textures[0] = Texture;
            mScene.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);
        }

        public bool RayHit(Ray ray, out float t, out Vector3 hitPos)
        {
            foreach (Triangle tri in mTriangles)
            {
                Vector3? uvw;
                float? pT = tri.Intersects(ray, Position, Scale * Rotation, out uvw);
                if (pT != null)
                {
                    t = pT.Value;
                    hitPos = (tri.A * uvw.Value.X) + (tri.B * uvw.Value.Y) + (tri.C * uvw.Value.Z);
                    hitPos = Vector3.Transform(hitPos + Position, Scale * Rotation);
                    return true;
                }
            }
            hitPos = new Vector3();
            t = 0;
            return false;
        }
    }
}
